#pragma once

#include "LockGuard.hpp"
#include "Log.hpp"
#include "InetAddr.hpp"
#include "Socket.hpp"

using namespace log_ns;
using namespace socket_ns;
enum
{
    SOCKET_ERROR = 1,
    BIND_ERROR,
    LISTEN_ERR
};

using task_t = std::function<void()>;
using service_t = std::function<std::string(std::string &reqstr)>; // 要执行的服务
class TcpServer
{
public:
    TcpServer(uint16_t port, service_t service)
        : _listensock(std::make_shared<TcpSoket>()),
          _port(port),
          _isrunning(false), 
          _service(service)
    {
        _listensock->BuildListenSocket(_port);
    }

    // 线程函数的参数类型
    class ThreadData
    {
    public:
        ThreadData(SockSPtr sockfd, InetAddr &addr, TcpServer *p)
            : _sockfd(sockfd),
              _addr(addr),
              _self(p)
        {
        }

    public:
        SockSPtr _sockfd;
        InetAddr _addr;
        TcpServer *_self;
    };

    void Loop()
    {
        _isrunning = true;
        while (_isrunning)
        {
            // 连接
            InetAddr client;
            SockSPtr newsock = _listensock->Acceptor(&client);
            if (newsock == nullptr) continue;

            // 与客户端建立连接，开始服务
            // v3, 多线程版本
            pthread_t tid;
            // 因为是静态成员函数，所以需要传递一个类对象指针，方便调用服务
            ThreadData *td = new ThreadData(newsock, client, this);
            pthread_create(&tid, nullptr, Excute, td);
        }
    }

    // 类成员函数的参数多了一个 this，所以设置为静态成员函数
    static void *Excute(void *args)
    {
        pthread_detach(pthread_self()); // 新线程分离，主线程不用进行等待
        ThreadData *td = static_cast<ThreadData *>(args);

        std::string reqstr;
        int n = td->_sockfd->Recv(&reqstr); // 默认读取的报文是完整的
        if (n > 0)
        {
            // 读取请求成功，执行服务，得到响应
            std::string respstr = td->_self->_service(reqstr);
            // 发送响应

            td->_sockfd->Send(respstr);
        }
        // 服务结束
        td->_sockfd->Close();
        delete td;
        return nullptr;
    }

    ~TcpServer()
    {
    }

private:
    SockSPtr _listensock;
    uint16_t _port;
    bool _isrunning;

    service_t _service;
};